Skip to content

fix(rateLimit): exempt all relation DELETE routes from IP rate limiter#1710

Merged
ClemRz merged 2 commits into
developfrom
fix/relation-delete-rate-limit
Jun 28, 2026
Merged

fix(rateLimit): exempt all relation DELETE routes from IP rate limiter#1710
ClemRz merged 2 commits into
developfrom
fix/relation-delete-rate-limit

Conversation

@ClemRz

@ClemRz ClemRz commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

🤔 What

🤷‍♂️ Why

The deleteRateLimit allows regular users only 1 DELETE request per hour per IP. This is far too aggressive for endpoints that only remove an association row (e.g., unlinking a document from an entrance, removing a caver from an organization). These endpoints don't destroy data — they remove a link between two existing entities. A user managing their associations could exhaust their hourly quota with a single action.

🔍 How

Added a RELATION_DELETE_PATTERNS array listing all 10 relation DELETE path regexes, and an isRelationDelete() helper used in the deleteRateLimit.skip function. When a request path matches any of the patterns, the destructive-action rate limit is skipped. The generalRateLimit still applies to these routes, so they're not unprotected.

Also addressed Paul's review suggestions from #1706:

  1. Added a test variant with req.token set (regular user) to mirror the real authenticated call path.
  2. Added a negative assertion: requests to /api/v1/entrances/42/cavers/7/extra (extending beyond the pattern) are still rate-limited (429).
  3. Fixed the inline comment: "tokenAuth ensures the caller is authenticated, and the controller enforces ownership/authorization."

🧪 Testing

npm run test -- --grep "Rate Limiter"

All 15 rate limiter tests pass, including the 3 new ones.

📸 Previews

N/A

- Extend skip logic to cover all 10 relation/association DELETE endpoints
- Add RELATION_DELETE_PATTERNS array for maintainability
- Add authenticated user test variant (mirrors real call path)
- Add negative assertion test for paths extending beyond relation routes
- Fix comment accuracy (tokenAuth = authentication, controller = ownership)

Closes #1707
@ClemRz ClemRz self-assigned this Jun 28, 2026
@ClemRz ClemRz requested a review from Paul-AUB June 28, 2026 17:52
Paul-AUB
Paul-AUB previously approved these changes Jun 28, 2026

@Paul-AUB Paul-AUB left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid, well-scoped change. All 10 RELATION_DELETE_PATTERNS were cross-checked against config/routes.js and each one maps to a real DELETE route with matching parameter arity. Since deleteRateLimit runs as a global middleware (config/http.js order array), req.path correctly resolves to the full /api/v1/... path, so the anchored regexes behave as intended. The new tests are a good improvement (authenticated variant + negative boundary assertion). No blocking issues found.

Suggestions (Should Consider)

  1. Regression coverage for destructive DELETEsconfig/rateLimit/rateLimiter.js:109-120 The new patterns correctly don't match single-segment destructive routes (e.g. DELETE /api/v1/entrances/:id), and the /extra negative test is a nice guard. Consider also adding one assertion that a genuinely destructive DELETE path is still rate-limited (returns 429), so a future broadening of RELATION_DELETE_PATTERNS can't silently exempt a destructive route.

  2. Pattern/route driftRELATION_DELETE_PATTERNS duplicates the relation-route list that also lives in config/routes.js. As relation endpoints are added, the two can drift (a new relation route would silently inherit the strict 1/h limit until someone remembers to update this array). Worth a short comment pointing maintainers here, or a follow-up to derive the list from a single source.

Nitpicks (Optional)

  1. Trailing slashconfig/rateLimit/rateLimiter.js:110-119 The $-anchored patterns won't match a trailing-slash variant (e.g. /api/v1/caves/1/documents/50/), which would fall through to the strict limiter. Real-world risk is low (clients don't send trailing slashes here), just noting the edge.

  2. Test setup duplicationtest/integration/2_utils/rateLimiter.test.js: The unauthenticated and authenticated exemption tests share most of their app/agent setup and the same RELATION_PATHS loop. Could be parameterized to reduce duplication, but it's perfectly readable as-is.

- Add regression test for destructive DELETE route still being rate-limited
- Add MAINTENANCE comment warning about pattern/route drift
@ClemRz

ClemRz commented Jun 28, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review @Paul-AUB! Addressed in 8a021f0:

Suggestion 2 (Regression coverage): Added a test asserting that DELETE /api/v1/entrances/42 (destructive single-segment route) is still rate-limited. This catches any future over-broadening of RELATION_DELETE_PATTERNS.

Suggestion 3 (Pattern/route drift): Added a MAINTENANCE: comment in the JSDoc above RELATION_DELETE_PATTERNS reminding to update the array when adding new relation DELETE routes.

Suggestions 4 & 5 (trailing slash, test duplication): Acknowledged but skipped — low risk and readable as-is per your own notes.

@ClemRz ClemRz merged commit f6d9c44 into develop Jun 28, 2026
3 checks passed
@ClemRz ClemRz deleted the fix/relation-delete-rate-limit branch June 28, 2026 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rate limit too strict on relation/association DELETE endpoints

2 participants